package ma.platform.server.student.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.enums.WriteDirectionEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.data.Rows;
import com.deepoove.poi.data.Tables;
import com.deepoove.poi.util.PoitlIOUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import ma.platform.server.common.oss.core.FileProperties;
import ma.platform.server.common.oss.core.FileTemplate;
import ma.platform.server.core.util.R;
import ma.platform.server.core.util.StreamUtils;
import ma.platform.server.student.dto.SchoolStaticesDto;
import ma.platform.server.student.dto.TbDateComboDto;
import ma.platform.server.student.entity.*;
import ma.platform.server.student.req.*;
import ma.platform.server.student.service.*;
import ma.platform.server.student.mapper.TbStudentComboMapper;
import ma.platform.server.student.vo.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Administrator
 * @description 针对表【tb_student_combo(学生套餐预约表)】的数据库操作Service实现
 * @createDate 2024-08-27 17:01:05
 */
@Service
public class TbStudentComboServiceImpl extends ServiceImpl<TbStudentComboMapper, TbStudentCombo>
        implements TbStudentComboService {

    @Resource
    private TbDateComboService tbDateComboService;

    @Resource
    private TbStudentService tbStudentService;

    @Resource
    private TbGradeService tbGradeService;

    @Resource
    private TbClassesService tbClassesService;

    @Resource
    private FileTemplate fileTemplate;

    @Resource
    private FileProperties properties;

    @Resource
    private TbSchoolService tbSchoolService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createResrve(CreateResrveReq req) {
        if (CollectionUtils.isEmpty(req.getComboIdList())) {
            return;
        }
        List<TbDateCombo> comboList = tbDateComboService.listByIds(req.getComboIdList());
        List<Date> dates = StreamUtils.convert2List(comboList, TbDateCombo::getDate);
        if (CollectionUtils.isEmpty(dates)) {
            return;
        }
        remove(Wrappers.<TbStudentCombo>lambdaQuery().eq(TbStudentCombo::getStudentId, req.getStudentId()).in(TbStudentCombo::getDate, dates));

        List<TbStudentCombo> tbStudentCombos = StreamUtils.convert2List(comboList, item -> {
            TbStudentCombo studentCombo = new TbStudentCombo();
            studentCombo.setComboId(item.getComboId());
            studentCombo.setDate(item.getDate());
            studentCombo.setDateComboId(item.getId());
            studentCombo.setStudentId(req.getStudentId());
            return studentCombo;
        });
        saveBatch(tbStudentCombos);
    }

    @Override
    public List<TbDateComboDto> listHistoryResrve(QueryHistoryResrveReq req) {
        return baseMapper.selectHistoryResrve(req);
    }

    @Override
    public Page<TbDateComboDto> pageStudentCombo(Page page, QueryStudentComboReq req) {

        return baseMapper.selectStudentComboPage(page, req);
    }

    @Override
    public Page<SchoolStaticesDto> schoolStatices(Page page, QueryStudentComboReq req) {
        return baseMapper.schoolStatices(page, req);
    }

    @Override
    public Page<SchoolStaticesDto> schoolDishStatices(Page page, QueryStudentComboReq req) {
        return baseMapper.schoolDishStatices(page, req);
    }

    @Override
    public Page<SchoolStaticesDto> gradeStatices(Page page, QueryStudentComboReq req) {
        return baseMapper.gradeStatices(page, req);
    }

    @Override
    public Page<SchoolStaticesDto> gradeDishStatices(Page page, QueryStudentComboReq req) {
        return baseMapper.gradeDishStatices(page, req);
    }

    @Override
    public Page<SchoolStaticesDto> classesStatices(Page page, QueryStudentComboReq req) {
        return baseMapper.classesStatices(page, req);
    }

    @Override
    public Page<SchoolStaticesDto> classesDishStatices(Page page, QueryStudentComboReq req) {
        return baseMapper.classesDishStatices(page, req);
    }

    @Override
    public List<SchoolExportVo> schoolStaticesExport(QueryStudentComboReq req) {
        return baseMapper.schoolStaticesExport(req);
    }

    @Override
    public List<SchoolDishExportVo> schoolDishStaticesExport(QueryStudentComboReq req) {
        return baseMapper.schoolDishStaticesExport(req);
    }

    @Override
    public List<GradeExportVo> gradeStaticesExport(QueryStudentComboReq req) {
        return baseMapper.gradeStaticesExport(req);
    }

    @Override
    public List<GradeDishExportVo> gradeDishStaticesExport(QueryStudentComboReq req) {
        return baseMapper.gradeDishStaticesExport(req);
    }

    @Override
    public List<ClassesExportVo> classesStaticesExport(QueryStudentComboReq req) {
        return baseMapper.classesStaticesExport(req);
    }

    @Override
    public List<ClassesDishExportVo> classesDishStaticesExport(QueryStudentComboReq req) {
        return baseMapper.classesDishStaticesExport(req);
    }

    @SneakyThrows
    @Override
    public void dowloadTag(HttpServletResponse response, QueryStudentComboTagReq req) {
        QueryStudentComboReq schoolReq = new QueryStudentComboReq();
        schoolReq.setSchoolId(req.getSchoolId());
        schoolReq.setStartTime(req.getDate());
        schoolReq.setEndTime(req.getDate());
        List<SchoolExportVo> schoolExport = baseMapper.schoolStaticesExport(schoolReq);
        if (CollectionUtils.isEmpty(schoolExport)) {
            return;
        }

        ComboTagVo comboTagVo = new ComboTagVo();
        comboTagVo.setSchoolName(schoolExport.get(0).getSchoolName());
        List<String> comboNames = StreamUtils.convert2List(schoolExport, SchoolExportVo::getComboName);
        RowRenderData schoolRow = Rows.of(comboNames.toArray(new String[]{})).textColor("FFFFFF")
                .bgColor("4472C4").center().create();


        RowRenderData schoolRowData = Rows.create(StreamUtils.convert2List(schoolExport, item -> String.valueOf(item.getCount())).toArray(new String[]{}));
        comboTagVo.setGradeTable(Tables.create(schoolRow, schoolRowData));

        QueryStudentComboReq classesReq = new QueryStudentComboReq();
        classesReq.setSchoolId(req.getSchoolId());
        classesReq.setStartTime(req.getDate());
        classesReq.setEndTime(req.getDate());
        List<ClassesExportVo> classesExportVos = baseMapper.classesStaticesExport(classesReq);
        List<TbGrade> gradeList = tbGradeService.list(Wrappers.<TbGrade>lambdaQuery().eq(TbGrade::getSchoolId, req.getSchoolId()).orderByAsc(TbGrade::getSortd));

        List<TbClasses> classesList = tbClassesService.list(Wrappers.<TbClasses>lambdaQuery().eq(TbClasses::getSchoolId, req.getSchoolId()));
        Map<Long, List<TbClasses>> classesMap = StreamUtils.getGroupMap(classesList, TbClasses::getGradeId);

        Map<Long, List<ClassesExportVo>> classesExcelMap = StreamUtils.getGroupMap(classesExportVos, ClassesExportVo::getClassesId);

        List<ComboTagItemVo> classessList = Lists.newArrayList();
        for (TbGrade tbGrade : gradeList) {
            List<TbClasses> tbClassesList = classesMap.getOrDefault(tbGrade.getId(), Lists.newArrayList());
            for (TbClasses tbClasses : tbClassesList) {
                List<ClassesExportVo> exportVoList = classesExcelMap.getOrDefault(tbClasses.getId(), Lists.newArrayList());
                if (CollectionUtils.isEmpty(exportVoList)) {
                    continue;
                }
                ComboTagItemVo comboTagItemVo = new ComboTagItemVo();
                comboTagItemVo.setClassesName(tbClasses.getClassesName());
                comboTagItemVo.setGradeName(tbGrade.getGradeName());
                comboTagItemVo.setClassesTable(Tables.create(Rows.of(StreamUtils.convert2List(exportVoList, ClassesExportVo::getComboName).toArray(new String[]{})).textColor("FFFFFF")
                                .bgColor("4472C4").center().create(),
                        Rows.create(StreamUtils.convert2List(exportVoList, item -> String.valueOf(item.getCount())).toArray(new String[]{}))));
                classessList.add(comboTagItemVo);
            }
        }
        comboTagVo.setClassessList(classessList);
        String templatePath = properties.getLocal().getBasePath() + "/template/tag.docx";
        XWPFTemplate xwpfTemplate = XWPFTemplate.compile(templatePath).render(BeanUtil.beanToMap(comboTagVo));
        response.setContentType("application/octet-stream");
        response.setHeader("Content-disposition", "attachment;filename=\"" + "tag.docx" + "\"");
        OutputStream out = response.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(out);
        xwpfTemplate.write(bos);
        bos.flush();
        out.flush();
        PoitlIOUtils.closeQuietlyMulti(xwpfTemplate, bos, out);
    }

    @SneakyThrows
    @Override
    public void dowloadClassTable(HttpServletResponse response, QueryStudentComboReq req) {
        TbSchool tbSchool = tbSchoolService.getById(req.getSchoolId());
        TbGrade tbGrade = tbGradeService.getById(req.getGradeId());
        TbClasses tbClasses = tbClassesService.getById(req.getClassesId());


        List<TbStudent> studentList = tbStudentService.list(Wrappers.<TbStudent>lambdaQuery().eq(TbStudent::getClassesId, tbClasses.getId()));
        List<Long> studentIdList = StreamUtils.convert2List(studentList, TbStudent::getId);
        List<TbStudentCombo> studentComboList = list(Wrappers.<TbStudentCombo>lambdaQuery()
                .in(TbStudentCombo::getStudentId, studentIdList).between(TbStudentCombo::getDate, req.getStartTime(), req.getEndTime()));
        if (CollectionUtils.isEmpty(studentComboList)) {
            throw new Exception("暂无数据");
        }


        Map<Long, TbStudent> studentMap = StreamUtils.getMap(studentList, TbStudent::getId);
        studentList = StreamUtils.filterList(studentList, item -> StringUtils.isNotBlank(item.getName()));
        List<Map<String, Object>> studentDataList = Lists.newArrayList();
        List<Map<String, Object>> comboDataList = Lists.newArrayList();
        Map<String, List<TbStudentCombo>> groupMap = StreamUtils.getGroupMap(studentComboList, item -> DateUtil.format(item.getDate(), "yyyy.MM.dd"));
        //groupMap根据时间排序
        groupMap = groupMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));

        for (TbStudent tbStudent : studentList) {
            Map<String, Object> studentDataMap = Maps.newHashMap();
            studentDataMap.put("studentNo", tbStudent.getStudentId());
            studentDataMap.put("studentName", tbStudent.getName());
            for (String date : groupMap.keySet()) {
                studentDataMap.put("comboName_" + DateUtil.format(DateUtil.parse(date, "yyyy.MM.dd"), "yyyyMMdd"),
                        "{comboName_" + tbStudent.getId() + "_" + DateUtil.format(DateUtil.parse(date, "yyyy.MM.dd"), "yyyyMMdd") + "}");
            }
            studentDataList.add(studentDataMap);
        }


        for (Map.Entry<String, List<TbStudentCombo>> entry : groupMap.entrySet()) {
            List<TbStudentCombo> tbStudentComboList = entry.getValue();
            Map<String, Object> comboDataMap = Maps.newHashMap();
            String kwy = DateUtil.format(DateUtil.parse(entry.getKey(), "yyyy.MM.dd"), "yyyyMMdd");
            for (TbStudentCombo tbStudentCombo : tbStudentComboList) {
                comboDataMap.put("comboName_" + tbStudentCombo.getStudentId() + "_" + kwy, Objects.equals(tbStudentCombo.getComboId(), 1L) ? "A" : "B");
            }
            comboDataMap.put("countA_" + kwy, tbStudentComboList.stream().filter(item -> Objects.equals(item.getComboId(), 1L)).count());
            comboDataMap.put("countB_" + kwy, tbStudentComboList.stream().filter(item -> Objects.equals(item.getComboId(), 2L)).count());
            comboDataList.add(comboDataMap);
        }

        String templatePath = properties.getLocal().getBasePath() + "/template/选餐统计表.xls";
        File tempFile = FileUtil.createTempFile(".xls", true);
        try (ExcelWriter excelWriter = EasyExcel.write(tempFile).withTemplate(templatePath).build()) {
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            FillConfig horizontal = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build();
            List<Map<String, Object>> comboDtList = Lists.newArrayList();
            Set<String> keySet = groupMap.keySet();
            Map<String, Object> baseMap = new HashMap<String, Object>();
            baseMap.put("schoolName", tbSchool.getSchoolName());
            baseMap.put("className", tbGrade.getGradeName() + tbClasses.getClassesName());
            baseMap.put("studentNo", "{st.studentNo}");
            baseMap.put("studentName", "{st.studentName}");
            for (String key : keySet) {
                Map<String, Object> map = Maps.newHashMap();
                map.put("date", key);
                map.put("tczl","套餐种类");
                map.put("comboName", "{st.comboName_" + DateUtil.format(DateUtil.parse(key, "yyyy.MM.dd"), "yyyyMMdd") + "}");
                map.put("countA", "{countA_" + DateUtil.format(DateUtil.parse(key, "yyyy.MM.dd"), "yyyyMMdd") + "}");
                map.put("countB", "{countB_" + DateUtil.format(DateUtil.parse(key, "yyyy.MM.dd"), "yyyyMMdd") + "}");
                comboDtList.add(map);
            }

            excelWriter.fill(new FillWrapper("comboDt", comboDtList), horizontal, writeSheet);
            excelWriter.fill(baseMap, writeSheet);
        }
        File tempFile1 = FileUtil.createTempFile(".xls", true);
        try (ExcelWriter excelWriter = EasyExcel.write(tempFile1).withTemplate(tempFile).build()) {
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            FillConfig horizontal = FillConfig.builder().direction(WriteDirectionEnum.VERTICAL).forceNewRow(Boolean.TRUE).build();
            Map<String, Object> map = Maps.newHashMap();
            for (String key : groupMap.keySet()) {

                map.put("countA_" + DateUtil.format(DateUtil.parse(key, "yyyy.MM.dd"), "yyyyMMdd"), "{countA_" + DateUtil.format(DateUtil.parse(key, "yyyy.MM.dd"), "yyyyMMdd") + "}");
                map.put("countB_" + DateUtil.format(DateUtil.parse(key, "yyyy.MM.dd"), "yyyyMMdd"), "{countB_" + DateUtil.format(DateUtil.parse(key, "yyyy.MM.dd"), "yyyyMMdd") + "}");
            }
            excelWriter.fill(new FillWrapper("st", studentDataList), horizontal, writeSheet);
            excelWriter.fill(map, writeSheet);
        }
        Map<String, Object> comboDataMap = Maps.newHashMap();
        try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).withTemplate(tempFile1).build()) {
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            for (Map<String, Object> combMap : comboDataList) {
                comboDataMap.putAll(combMap);
            }

         excelWriter.fill(comboDataMap,writeSheet);
        }

        response.setContentType("application/octet-stream");
        response.setHeader("Content-disposition", "attachment;filename=\"" + "选餐统计表.xls" + "\"");
    }
}




